package com.srmt.document.feishu.internal.writer;

import com.lark.oapi.service.docx.v1.model.*;
import com.srmt.document.exception.ContentException;
import com.srmt.document.feishu.internal.FeishuTextElementLocator;
import com.srmt.document.feishu.internal.core.BlockContext;
import com.srmt.document.feishu.internal.core.BlockUtils;
import com.srmt.feishu.client.FeishuClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.regex.PatternSyntaxException;

/**
 * 文本操作服务
 * 从FeishuContentWriter中抽取的文本相关操作
 * 
 * @author srmt
 * @since 1.1.0
 */
public class TextOperationService {
    
    private static final Logger logger = LoggerFactory.getLogger(TextOperationService.class);
    
    private final FeishuClient client;
    private final FeishuTextElementLocator textElementLocator;

    public TextOperationService(FeishuClient client) {
        this.client = client;
        this.textElementLocator = new FeishuTextElementLocator(client);
    }
    
    /**
     * 在指定锚点文本后追加文本
     */
    public void appendTextAfter(String docId, String anchorText, String text) throws ContentException {
        logger.debug("在文档 {} 中锚点 '{}' 后追加文本", anchorText, docId);
        
        try {
            performAppendTextAfter(docId, anchorText, text);
        } catch (ContentException e) {
            throw e;
        } catch (Exception e) {
            throw new ContentException("追加文本失败: " + e.getMessage(), e);
        }
    }
    
    private void performAppendTextAfter(String docId, String anchorText, String text) throws Exception {
        // 创建上下文（唯一的API调用）
        BlockContext context = new BlockContext(client, docId);
        
        if (anchorText == null || anchorText.isEmpty()) {
            // 如果没有锚点，获取页面根block并添加新的Block
            appendTextToEnd(docId, text, context);
        } else {
            // 查找锚点Block并追加文本
            appendTextAfterAnchor(docId, anchorText, text, context);
        }
        
        logger.info("文本成功追加到锚点 '{}' 后", anchorText);
    }
    
    /**
     * 在指定锚点文本前插入文本
     */
    public void insertTextBefore(String docId, String anchorText, String text) throws ContentException {
        logger.debug("在文档 {} 中锚点 '{}' 前插入文本", anchorText, docId);
        
        try {
            performInsertTextBefore(docId, anchorText, text);
        } catch (ContentException e) {
            throw e;
        } catch (Exception e) {
            throw new ContentException("插入文本失败: " + e.getMessage(), e);
        }
    }
    
    private void performInsertTextBefore(String docId, String anchorText, String text) throws Exception {
        // 创建上下文
        BlockContext context = new BlockContext(client, docId);
        
        if (anchorText == null || anchorText.isEmpty()) {
            // 如果没有锚点，在文档开头插入
            insertTextAtBeginning(docId, text, context);
        } else {
            // 查找锚点Block并在前面插入文本
            insertTextBeforeAnchor(docId, anchorText, text, context);
        }
        
        logger.info("文本成功插入到锚点 '{}' 前", anchorText);
    }
    
    /**
     * 替换文档中的文本
     */
    public void replaceText(String docId, String oldText, String newText) throws ContentException {
        logger.debug("在文档 {} 中将文本 '{}' 替换为 '{}'", oldText, newText, docId);
        
        try {
            performReplaceText(docId, oldText, newText);
        } catch (ContentException e) {
            throw e;
        } catch (Exception e) {
            throw new ContentException("替换文本失败: " + e.getMessage(), e);
        }
    }
    
    private void performReplaceText(String docId, String oldText, String newText) throws Exception {
        // 创建上下文
        BlockContext context = new BlockContext(client, docId);
        
        // 使用TextElementLocator查找所有出现的位置
        List<FeishuTextElementLocator.TextElementLocation> locations = 
            textElementLocator.findAllTextElements(context.getDocumentId(), oldText);
        
        if (locations.isEmpty()) {
            // 文本不存在时应该抛出异常
            throw new ContentException("未找到要替换的文本: " + oldText);
        }
        
        // 替换所有找到的文本
        for (FeishuTextElementLocator.TextElementLocation location : locations) {
            replaceTextAtLocation(docId, location, oldText, newText);
        }
        
        logger.info("将 {} 处的 '{}' 替换为 '{}'", locations.size(), oldText, newText);
    }
    
    /**
     * 替换所有匹配的文本
     */
    public int replaceAllText(String docId, String oldText, String newText) throws ContentException {
        logger.debug("在文档 {} 中替换所有 '{}' 为 '{}'", oldText, newText, docId);
        
        try {
            return performReplaceAllText(docId, oldText, newText);
        } catch (ContentException e) {
            throw e;
        } catch (Exception e) {
            throw new ContentException("替换所有文本失败: " + e.getMessage(), e);
        }
    }
    
    private int performReplaceAllText(String docId, String oldText, String newText) throws Exception {
        // 创建上下文
        BlockContext context = new BlockContext(client, docId);
        
        // 查找所有匹配的文本
        List<FeishuTextElementLocator.TextElementLocation> locations = 
            textElementLocator.findAllTextElements(context.getDocumentId(), oldText);
        
        if (locations.isEmpty()) {
            logger.warn("文档中未找到文本 '{}'", oldText);
            return 0;
        }
        
        // 批量替换
        for (FeishuTextElementLocator.TextElementLocation location : locations) {
            replaceTextAtLocation(docId, location, oldText, newText);
        }
        
        logger.info("将 {} 处的 '{}' 替换为 '{}'", locations.size(), oldText, newText);
        return locations.size();
    }
    
    // ========== 辅助方法 ==========
    
    private void appendTextToEnd(String docId, String text, BlockContext context) throws Exception {
        Block pageBlock = context.getPageBlock();
        if (pageBlock == null) {
            throw new ContentException("未找到页面块");
        }
        
        // 创建文本Block
        TextElement[] elements = BlockUtils.createTextElements(text);
        Text textBlock = Text.newBuilder()
                .elements(elements)
                .build();
        
        Block newBlock = Block.newBuilder()
                .blockType(BlockUtils.BLOCK_TYPE_TEXT)
                .text(textBlock)
                .build();
        
        // 在指定Block后添加新Block
        CreateDocumentBlockChildrenReq req = CreateDocumentBlockChildrenReq.newBuilder()
                .documentId(docId)
                .blockId(pageBlock.getBlockId())
                .createDocumentBlockChildrenReqBody(CreateDocumentBlockChildrenReqBody.newBuilder()
                        .children(new Block[]{newBlock})
                        .index(-1) // 添加到末尾
                        .build())
                .build();

        // createDocumentBlockChildren现在直接返回数据体，失败时抛出FeishuApiException
        client.docx().createDocumentBlockChildren(req);
    }
    
    private void appendTextAfterAnchor(String docId, String anchorText, String text, BlockContext context) 
            throws Exception {
        // 查找锚点Block
        Block anchorBlock = context.findBlockByAnchor(anchorText);
        if (anchorBlock == null) {
            // 锚点不存在时应该抛出异常
            throw new ContentException("Anchor text 未找到: " + anchorText);
        }
        
        // 获取锚点的文本容器
        Text textContainer = BlockUtils.getTextFromBlock(anchorBlock);
        if (textContainer == null || textContainer.getElements() == null) {
            throw new ContentException("锚点块没有文本元素");
        }
        
        // 在TextElement级别插入文本
        List<TextElement> newElements = new ArrayList<>();
        TextElement[] existingElements = textContainer.getElements();
        boolean anchorFound = false;
        
        for (TextElement element : existingElements) {
            newElements.add(element);
            String content = BlockUtils.extractTextFromTextElement(element);
            if (content.contains(anchorText)) {
                // 在锚点后添加新文本
                TextElement[] additionalElements = BlockUtils.createTextElements(text);
                newElements.addAll(Arrays.asList(additionalElements));
                anchorFound = true;
            }
        }
        
        if (!anchorFound) {
            // 如果没有找到锚点，在末尾添加
            TextElement[] additionalElements = BlockUtils.createTextElements(text);
            newElements.addAll(Arrays.asList(additionalElements));
        }
        
        // 更新Block的文本元素
        updateBlockTextElements(docId, anchorBlock.getBlockId(), newElements);
    }
    
    private void insertTextAtBeginning(String docId, String text, BlockContext context) throws Exception {
        Block pageBlock = context.getPageBlock();
        if (pageBlock == null) {
            throw new ContentException("未找到页面块");
        }
        
        // 创建新的文本Block
        TextElement[] elements = BlockUtils.createTextElements(text);
        Text textBlock = Text.newBuilder()
                .elements(elements)
                .build();
        
        Block newBlock = Block.newBuilder()
                .blockType(BlockUtils.BLOCK_TYPE_TEXT)
                .text(textBlock)
                .build();
        
        // 在页面Block的开头插入
        CreateDocumentBlockChildrenReq req = CreateDocumentBlockChildrenReq.newBuilder()
                .documentId(docId)
                .blockId(pageBlock.getBlockId())
                .createDocumentBlockChildrenReqBody(CreateDocumentBlockChildrenReqBody.newBuilder()
                        .children(new Block[]{newBlock})
                        .index(0) // 插入到开头
                        .build())
                .build();

        // createDocumentBlockChildren现在直接返回数据体，失败时抛出FeishuApiException
        client.docx().createDocumentBlockChildren(req);

        logger.info("文本已插入到文档开头");
    }
    
    private void insertTextBeforeAnchor(String docId, String anchorText, String text, BlockContext context) 
            throws Exception {
        // 查找锚点Block
        Block anchorBlock = context.findBlockByAnchor(anchorText);
        if (anchorBlock == null) {
            // 锚点不存在时应该抛出异常
            throw new ContentException("Anchor text 未找到: " + anchorText);
        }
        
        // 获取锚点的文本容器
        Text textContainer = BlockUtils.getTextFromBlock(anchorBlock);
        if (textContainer == null || textContainer.getElements() == null) {
            throw new ContentException("锚点块没有文本元素");
        }
        
        // 在TextElement级别插入文本
        List<TextElement> newElements = new ArrayList<>();
        TextElement[] existingElements = textContainer.getElements();
        boolean anchorFound = false;
        
        for (TextElement element : existingElements) {
            String content = BlockUtils.extractTextFromTextElement(element);
            if (!anchorFound && content.contains(anchorText)) {
                // 在锚点前添加新文本
                TextElement[] additionalElements = BlockUtils.createTextElements(text);
                newElements.addAll(Arrays.asList(additionalElements));
                anchorFound = true;
            }
            newElements.add(element);
        }
        
        if (!anchorFound) {
            // 如果没有找到锚点，在开头添加
            TextElement[] additionalElements = BlockUtils.createTextElements(text);
            List<TextElement> tempList = new ArrayList<>(Arrays.asList(additionalElements));
            tempList.addAll(newElements);
            newElements = tempList;
        }
        
        // 更新Block的文本元素
        updateBlockTextElements(docId, anchorBlock.getBlockId(), newElements);
    }
    
    private void replaceTextAtLocation(String docId, FeishuTextElementLocator.TextElementLocation location, 
                                      String oldText, String newText) throws Exception {
        Block block = location.getBlock();
        Text textContainer = BlockUtils.getTextFromBlock(block);
        
        if (textContainer == null || textContainer.getElements() == null) {
            return;
        }
        
        // 替换文本元素中的内容
        List<TextElement> newElements = new ArrayList<>();
        for (TextElement element : textContainer.getElements()) {
            if (element.getTextRun() != null && element.getTextRun().getContent() != null) {
                String content = element.getTextRun().getContent();
                if (content.contains(oldText)) {
                    // 替换文本
                    String replacedContent = content.replace(oldText, newText);
                    TextRun newTextRun = TextRun.newBuilder()
                            .content(replacedContent)
                            .textElementStyle(element.getTextRun().getTextElementStyle())
                            .build();
                    TextElement newElement = TextElement.newBuilder()
                            .textRun(newTextRun)
                            .build();
                    newElements.add(newElement);
                } else {
                    newElements.add(element);
                }
            } else {
                newElements.add(element);
            }
        }
        
        // 更新Block的文本元素
        updateBlockTextElements(docId, block.getBlockId(), newElements);
    }
    
    private void updateBlockTextElements(String docId, String blockId, List<TextElement> elements) 
            throws Exception {
        UpdateTextElementsRequest updateTextElementsReq = UpdateTextElementsRequest.newBuilder()
                .elements(elements.toArray(new TextElement[0]))
                .build();
        
        UpdateBlockRequest updateReq = UpdateBlockRequest.newBuilder()
                .blockId(blockId)
                .updateTextElements(updateTextElementsReq)
                .build();
        
        PatchDocumentBlockReq patchReq = PatchDocumentBlockReq.newBuilder()
                .documentId(docId)
                .blockId(blockId)
                .updateBlockRequest(updateReq)
                .build();

        // patchDocumentBlock现在直接返回Block对象，失败时抛出FeishuApiException
        client.docx().patchDocumentBlock(patchReq);
    }
    
    /**
     * 使用正则表达式替换匹配的文本内容
     * 
     * @param docId 文档ID
     * @param pattern 正则表达式模式
     * @param replacement 替换文本（支持捕获组引用如$1, $2）
     * @return 替换的次数
     * @throws ContentException 操作失败时抛出
     * @since 1.6.0
     */
    public int replaceTextByPattern(String docId, String pattern, String replacement) throws ContentException {
        logger.debug("按模式替换文本 '{}' with '{}' in document: {}", pattern, replacement, docId);
        
        try {
            return performReplaceTextByPattern(docId, pattern, replacement);
        } catch (PatternSyntaxException e) {
            throw new ContentException("无效 regex pattern: " + pattern, e);
        } catch (ContentException e) {
            throw e;
        } catch (Exception e) {
            throw new ContentException("按模式替换文本失败: " + e.getMessage(), e);
        }
    }
    
    private int performReplaceTextByPattern(String docId, String pattern, String replacement) throws Exception {
        // 1. 编译正则表达式
        Pattern regex = Pattern.compile(pattern);
        
        // 2. 创建上下文
        BlockContext context = new BlockContext(client, docId);
        
        // 3. 遍历所有blocks查找并替换匹配的文本
        int totalReplacements = 0;
        List<BlockUpdateRequest> blockUpdates = new ArrayList<>();
        
        for (Block block : context.getBlocks()) {
            Text textContainer = BlockUtils.getTextFromBlock(block);
            if (textContainer == null || textContainer.getElements() == null) {
                continue;
            }
            
            boolean blockModified = false;
            List<TextElement> newElements = new ArrayList<>();
            
            for (TextElement element : textContainer.getElements()) {
                if (element.getTextRun() != null && element.getTextRun().getContent() != null) {
                    String content = element.getTextRun().getContent();
                    Matcher matcher = regex.matcher(content);
                    
                    // 先检查是否有匹配
                    if (matcher.find()) {
                        // 重置matcher以计算替换次数
                        matcher.reset();
                        int replacementCount = 0;
                        while (matcher.find()) {
                            replacementCount++;
                        }
                        totalReplacements += replacementCount;
                        
                        // 执行替换
                        matcher.reset();
                        String replacedContent = matcher.replaceAll(replacement);
                        
                        // 创建新的TextElement
                        TextRun newTextRun = TextRun.newBuilder()
                                .content(replacedContent)
                                .textElementStyle(element.getTextRun().getTextElementStyle())
                                .build();
                        TextElement newElement = TextElement.newBuilder()
                                .textRun(newTextRun)
                                .build();
                        newElements.add(newElement);
                        blockModified = true;
                    } else {
                        newElements.add(element);
                    }
                } else {
                    newElements.add(element);
                }
            }
            
            // 如果block被修改，保存更新请求
            if (blockModified) {
                blockUpdates.add(new BlockUpdateRequest(block.getBlockId(), newElements));
            }
        }
        
        // 批量更新所有修改的blocks
        for (BlockUpdateRequest update : blockUpdates) {
            updateBlockTextElements(docId, update.blockId, update.elements);
        }
        
        if (totalReplacements == 0) {
            logger.warn("文档中未找到模式 '{}'", pattern);
        } else {
            logger.info("使用模式'{}'替换了{}处", pattern, totalReplacements);
        }
        
        return totalReplacements;
    }
    
    // 辅助类用于存储block更新请求
    private static class BlockUpdateRequest {
        final String blockId;
        final List<TextElement> elements;
        
        BlockUpdateRequest(String blockId, List<TextElement> elements) {
            this.blockId = blockId;
            this.elements = elements;
        }
    }
}